@dijitrak/react-nextjs-seo-plugin
Version:
A modern, user-friendly SEO plugin for React and Next.js with multilingual support and comprehensive optimization tools
222 lines (190 loc) • 6.84 kB
text/typescript
/**
* Meta etiketleri işlemleri
*/
import { SEOMetaData, LanguageMetadata } from '../types';
import type { Metadata } from 'next';
/**
* Meta etiketleri oluşturur
* @param metaData SEO meta verileri
* @param baseUrl Temel site URL'si
* @returns HTML meta etiketleri
*/
export function generateMetaTags(metaData: SEOMetaData, baseUrl: string = ''): string {
// Boş meta verileri için varsayılan değerleri ekle
const completeMeta: SEOMetaData = {
title: '',
description: '',
keywords: '',
allowIndex: true,
allowFollow: true,
canonicalUrl: '',
ogTitle: '',
ogDescription: '',
ogImage: '',
ogType: 'website',
twitterTitle: '',
twitterDescription: '',
twitterImage: '',
twitterCard: 'summary_large_image',
language: 'en',
// Özellikleri metaData'dan ekle, var olanları üzerine yaz
...metaData
};
let tags = '';
// Temel meta etiketleri
tags += `<title>${completeMeta.title}</title>\n`;
tags += `<meta name="description" content="${completeMeta.description}" />\n`;
if (completeMeta.keywords) {
tags += `<meta name="keywords" content="${completeMeta.keywords}" />\n`;
}
// Dil
if (completeMeta.language) {
tags += `<meta http-equiv="content-language" content="${completeMeta.language}" />\n`;
}
// Robots meta etiketi
const robotsValue = `${completeMeta.allowIndex ? 'index' : 'noindex'}, ${completeMeta.allowFollow ? 'follow' : 'nofollow'}`;
tags += `<meta name="robots" content="${robotsValue}" />\n`;
// Canonical link
if (completeMeta.canonicalUrl) {
let canonicalUrl = completeMeta.canonicalUrl;
// Eğer başında http yoksa ve baseUrl verilmişse birleştir
if (!canonicalUrl.startsWith('http') && baseUrl) {
canonicalUrl = baseUrl.replace(/\/$/, '') + (canonicalUrl.startsWith('/') ? canonicalUrl : `/${canonicalUrl}`);
}
tags += `<link rel="canonical" href="${canonicalUrl}" />\n`;
}
// Open Graph meta etiketleri
tags += `<meta property="og:title" content="${completeMeta.ogTitle || completeMeta.title}" />\n`;
tags += `<meta property="og:description" content="${completeMeta.ogDescription || completeMeta.description}" />\n`;
if (completeMeta.ogImage) {
let ogImage = completeMeta.ogImage;
// Eğer başında http yoksa ve baseUrl verilmişse birleştir
if (!ogImage.startsWith('http') && baseUrl) {
ogImage = baseUrl.replace(/\/$/, '') + (ogImage.startsWith('/') ? ogImage : `/${ogImage}`);
}
tags += `<meta property="og:image" content="${ogImage}" />\n`;
}
if (completeMeta.ogType) {
tags += `<meta property="og:type" content="${completeMeta.ogType}" />\n`;
}
// Twitter Card meta etiketleri
if (completeMeta.twitterCard) {
tags += `<meta name="twitter:card" content="${completeMeta.twitterCard}" />\n`;
}
tags += `<meta name="twitter:title" content="${completeMeta.twitterTitle || completeMeta.ogTitle || completeMeta.title}" />\n`;
tags += `<meta name="twitter:description" content="${completeMeta.twitterDescription || completeMeta.ogDescription || completeMeta.description}" />\n`;
if (completeMeta.twitterImage || completeMeta.ogImage) {
let twitterImage = completeMeta.twitterImage || completeMeta.ogImage;
// Eğer başında http yoksa ve baseUrl verilmişse birleştir
if (twitterImage && !twitterImage.startsWith('http') && baseUrl) {
twitterImage = baseUrl.replace(/\/$/, '') + (twitterImage.startsWith('/') ? twitterImage : `/${twitterImage}`);
}
tags += `<meta name="twitter:image" content="${twitterImage}" />\n`;
}
// Site URL
if (baseUrl) {
tags += `<meta property="og:url" content="${baseUrl}" />\n`;
}
return tags;
}
/**
* Hreflang etiketleri oluşturur
* @param languageMetadata Dil metadata bilgileri
* @param baseUrl Temel site URL'si
* @returns HTML hreflang etiketleri
*/
export function generateHreflangTags(languageMetadata: LanguageMetadata, baseUrl: string = ''): string {
if (!languageMetadata) return '';
let tags = '';
// Ana dil için hreflang etiketi
if (languageMetadata.primary) {
const href = baseUrl || '/';
tags += `<link rel="alternate" hreflang="${languageMetadata.primary}" href="${href}" />\n`;
// x-default için hreflang etiketi (varsayılan dil)
tags += `<link rel="alternate" hreflang="x-default" href="${href}" />\n`;
}
// Alternatif diller için hreflang etiketleri
if (languageMetadata.alternate && languageMetadata.alternate.length > 0) {
languageMetadata.alternate.forEach(alt => {
tags += `<link rel="alternate" hreflang="${alt.hrefLang}" href="${alt.href}" />\n`;
});
}
return tags;
}
/**
* Next.js App Router için Metadata nesnesini oluşturur
* @param props Metadata nesne parametreleri
* @returns Next.js Metadata nesnesi
*/
export function generateNextMetadata(props: {
title?: string;
description?: string;
keywords?: string | string[];
openGraph?: {
title?: string;
description?: string;
url?: string;
siteName?: string;
images?: Array<{
url: string;
width?: number;
height?: number;
alt?: string;
}>;
type?: string;
};
twitter?: {
card?: 'summary' | 'summary_large_image' | 'app' | 'player';
title?: string;
description?: string;
creator?: string;
images?: string[];
};
languageMetadata?: LanguageMetadata;
}): Metadata {
const {
title,
description,
keywords,
openGraph,
twitter,
languageMetadata
} = props;
const metadata: Metadata = {
// title ve description özelliklerini koşullu olarak ekleyelim
...(title ? { title } : {}),
...(description ? { description } : {}),
...(keywords ? { keywords } : {})
};
// Open Graph metadata
if (openGraph || title || description) {
metadata.openGraph = {
title: openGraph?.title || title || '',
description: openGraph?.description || description || '',
...openGraph
};
}
// Twitter metadata
if (twitter || title || description) {
metadata.twitter = {
title: twitter?.title || openGraph?.title || title || '',
description: twitter?.description || openGraph?.description || description || '',
card: twitter?.card || 'summary_large_image',
...twitter
};
}
// Alternatif dil bağlantıları
if (languageMetadata && languageMetadata.alternate && languageMetadata.alternate.length > 0) {
const alternates: Record<string, any> = {
languages: {}
};
if (languageMetadata.primary) {
alternates.languages['x-default'] = '/';
}
languageMetadata.alternate.forEach(alt => {
alternates.languages[alt.hrefLang] = alt.href;
});
metadata.alternates = alternates;
}
return metadata;
}