feat: improve SEO with podcast JSON-LD, canonical and meta descriptions
This commit is contained in:
+4
-2
@@ -124,7 +124,8 @@ Toutes ces sources sont modifiables dans `includes/config.local.php` (voir <<fr-
|
||||
|
||||
==== 🔍 SEO et données structurées
|
||||
|
||||
- *JSON-LD* généré automatiquement : `WebSite` (avec `SearchAction`), `VideoObject`, `CollectionPage`, `BreadcrumbList`
|
||||
- *JSON-LD* généré automatiquement : `WebSite` (avec `SearchAction`), `PodcastSeries` et `PodcastEpisode` (avec `AudioObject`) pour le podcast Castopod, `VideoObject` (avec `embedUrl`), `CollectionPage`, `BreadcrumbList`, `Organization`
|
||||
- *Meta descriptions* sur toutes les pages et *URL canoniques* (`link rel="canonical"`) ; pages de résultats de recherche en `noindex, follow`
|
||||
- Balises *Open Graph* et *Twitter Cards*
|
||||
- `sitemap.xml` et `robots.txt` fournis en exemples
|
||||
- Prêt pour *Plausible Analytics* (voir <<fr-analytics,Analytics>>) : désactivé par défaut, sans cookies et conforme RGPD
|
||||
@@ -1051,7 +1052,8 @@ All of these sources can be changed in `includes/config.local.php` (see <<en-con
|
||||
|
||||
==== 🔍 SEO and structured data
|
||||
|
||||
- Automatically generated *JSON-LD*: `WebSite` (with `SearchAction`), `VideoObject`, `CollectionPage`, `BreadcrumbList`
|
||||
- Automatically generated *JSON-LD*: `WebSite` (with `SearchAction`), `PodcastSeries` and `PodcastEpisode` (with `AudioObject`) for the Castopod podcast, `VideoObject` (with `embedUrl`), `CollectionPage`, `BreadcrumbList`, `Organization`
|
||||
- *Meta descriptions* on every page and *canonical URLs* (`link rel="canonical"`); search result pages set to `noindex, follow`
|
||||
- *Open Graph* and *Twitter Cards* meta tags
|
||||
- `sitemap.xml` and `robots.txt` provided as samples
|
||||
- Ready for *Plausible Analytics* (see <<en-analytics,Analytics>>): disabled by default, cookie-free and GDPR-compliant
|
||||
|
||||
+4
-2
@@ -43,6 +43,8 @@ if ($categoryId && isset($allCategories[$categoryId])) {
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="csrf-token" content="<?php echo generateCSRFToken(); ?>">
|
||||
<title><?php echo htmlspecialchars($categoryName); ?> - <?php echo SITE_NAME; ?></title>
|
||||
<meta name="description" content="Découvrez toutes les vidéos de la catégorie <?php echo htmlspecialchars($categoryName); ?> sur <?php echo SITE_NAME; ?>. Contenu multimédia de qualité et exclusif.">
|
||||
<link rel="canonical" href="<?php echo getBaseUrl() . '/categories.php?id=' . $categoryId; ?>">
|
||||
<link rel="stylesheet" href="css/styles.css?v=<?php echo filemtime('css/styles.css'); ?>">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.0.1/css/all.min.css">
|
||||
|
||||
@@ -52,7 +54,7 @@ if ($categoryId && isset($allCategories[$categoryId])) {
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="img/favicon-16x16.png">
|
||||
<link rel="manifest" href="site.webmanifest">
|
||||
<link rel="icon" type="image/x-icon" href="img/favicon.ico">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
<meta name="theme-color" content="#FF0000">
|
||||
|
||||
<!-- Open Graph Meta Tags -->
|
||||
<meta property="og:title" content="Catégorie : <?php echo htmlspecialchars($categoryName); ?> - <?php echo SITE_NAME; ?>">
|
||||
@@ -112,7 +114,7 @@ if ($categoryId && isset($allCategories[$categoryId])) {
|
||||
<div class="section-logo">
|
||||
<img src="img/logo.png" alt="<?php echo SITE_NAME; ?>">
|
||||
</div>
|
||||
<h2 class="section-title">Catégorie : <?php echo htmlspecialchars($categoryName); ?></h2>
|
||||
<h1 class="section-title">Catégorie : <?php echo htmlspecialchars($categoryName); ?></h1>
|
||||
</div>
|
||||
|
||||
<?php if (empty($videos)): ?>
|
||||
|
||||
@@ -13,6 +13,8 @@ setSecurityHeaders();
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="csrf-token" content="<?php echo generateCSRFToken(); ?>">
|
||||
<title><?php echo SITE_NAME; ?> - Ouverture prochaine</title>
|
||||
<meta name="description" content="<?php echo htmlspecialchars(SITE_DESCRIPTION); ?> Ouverture prochaine.">
|
||||
<link rel="canonical" href="<?php echo 'https://' . $_SERVER['HTTP_HOST'] . '/countdown.php'; ?>">
|
||||
|
||||
<!-- Styles -->
|
||||
<link rel="stylesheet" href="css/countdown.css?v=<?php echo filemtime('css/countdown.css'); ?>">
|
||||
|
||||
+5
-3
@@ -23,6 +23,8 @@ $liveStream = getLiveStream();
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Direct - <?php echo SITE_NAME; ?></title>
|
||||
<meta name="description" content="Suivez nos diffusions en direct sur <?php echo SITE_NAME; ?>. Contenu en temps réel, discussions et événements exclusifs.">
|
||||
<link rel="canonical" href="<?php echo getBaseUrl(); ?>/direct.php">
|
||||
<link rel="stylesheet" href="css/styles.css?v=<?php echo filemtime('css/styles.css'); ?>">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.0.1/css/all.min.css">
|
||||
|
||||
@@ -32,7 +34,7 @@ $liveStream = getLiveStream();
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="img/favicon-16x16.png">
|
||||
<link rel="manifest" href="site.webmanifest">
|
||||
<link rel="icon" type="image/x-icon" href="img/favicon.ico">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
<meta name="theme-color" content="#FF0000">
|
||||
|
||||
<!-- Open Graph Meta Tags -->
|
||||
<meta property="og:title" content="Direct - <?php echo SITE_NAME; ?>">
|
||||
@@ -191,7 +193,7 @@ $liveStream = getLiveStream();
|
||||
$dynamicTitle = NEXT_LIVE_TITLE;
|
||||
}
|
||||
?>
|
||||
<h2><?php echo htmlspecialchars($dynamicTitle); ?></h2>
|
||||
<h1><?php echo htmlspecialchars($dynamicTitle); ?></h1>
|
||||
<?php
|
||||
if (!empty(NEXT_LIVE_DATE)) {
|
||||
$liveHour = $liveDate->format('H\hi');
|
||||
@@ -260,7 +262,7 @@ $liveStream = getLiveStream();
|
||||
?>
|
||||
<div class="no-live-message">
|
||||
<i class="fas fa-tv"></i>
|
||||
<h2>Aucun direct en cours</h2>
|
||||
<h1>Aucun direct en cours</h1>
|
||||
<p>Revenez plus tard pour découvrir nos prochaines diffusions en direct.</p>
|
||||
<a href="index.php" class="btn-primary">Retour à l'accueil</a>
|
||||
</div>
|
||||
|
||||
+23
-14
@@ -16,6 +16,7 @@
|
||||
|
||||
require_once 'includes/config.php';
|
||||
require_once 'includes/security.php';
|
||||
require_once 'includes/structured-data.php';
|
||||
|
||||
// Vérifier si les dons sont activés
|
||||
if (!defined('DONATIONS_ENABLED') || !DONATIONS_ENABLED) {
|
||||
@@ -59,6 +60,7 @@ $stripeMonthlyLinks = defined('STRIPE_MONTHLY_LINKS') ? STRIPE_MONTHLY_LINKS : [
|
||||
<!-- PERSONNALISEZ: Titre et description de votre page de dons -->
|
||||
<title>Soutenir <?php echo ORGANIZATION_NAME; ?> - Dons</title>
|
||||
<meta name="description" content="Soutenez <?php echo ORGANIZATION_NAME; ?> par un don. Chaque contribution compte pour maintenir le hub multimédia du podcast.">
|
||||
<link rel="canonical" href="<?php echo getBaseUrl() . '/dons.php'; ?>">
|
||||
|
||||
<!-- Styles -->
|
||||
<link rel="stylesheet" href="css/styles.css?v=<?php echo filemtime('css/styles.css'); ?>">
|
||||
@@ -76,24 +78,31 @@ $stripeMonthlyLinks = defined('STRIPE_MONTHLY_LINKS') ? STRIPE_MONTHLY_LINKS : [
|
||||
<!-- Open Graph Meta Tags -->
|
||||
<meta property="og:title" content="Soutenir <?php echo ORGANIZATION_NAME; ?>">
|
||||
<meta property="og:description" content="Soutenez <?php echo ORGANIZATION_NAME; ?> par un don et aidez-nous à maintenir le hub multimédia du podcast.">
|
||||
<meta property="og:image" content="<?php echo 'https://' . $_SERVER['HTTP_HOST'] . '/img/logo.png'; ?>">
|
||||
<meta property="og:url" content="<?php echo 'https://' . $_SERVER['HTTP_HOST'] . '/dons.php'; ?>">
|
||||
<meta property="og:image" content="<?php echo getBaseUrl() . '/img/logo.png'; ?>">
|
||||
<meta property="og:url" content="<?php echo getBaseUrl() . '/dons.php'; ?>">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="<?php echo SITE_NAME; ?>">
|
||||
<meta property="og:locale" content="fr_FR">
|
||||
|
||||
<!-- Twitter Card Meta Tags -->
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="Soutenir <?php echo ORGANIZATION_NAME; ?>">
|
||||
<meta name="twitter:description" content="Soutenez <?php echo ORGANIZATION_NAME; ?> par un don et aidez-nous à maintenir le hub multimédia du podcast.">
|
||||
<meta name="twitter:image" content="<?php echo getBaseUrl() . '/img/logo.png'; ?>">
|
||||
|
||||
<!-- Schema.org pour les dons -->
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "Organization",
|
||||
"name": "<?php echo SITE_NAME; ?>",
|
||||
"description": "<?php echo SITE_DESCRIPTION; ?>",
|
||||
"url": "<?php echo 'https://' . $_SERVER['HTTP_HOST']; ?>",
|
||||
"potentialAction": {
|
||||
"@type": "DonateAction"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<?php
|
||||
outputJsonLd(json_encode([
|
||||
"@context" => "https://schema.org",
|
||||
"@type" => "Organization",
|
||||
"name" => SITE_NAME,
|
||||
"description" => SITE_DESCRIPTION,
|
||||
"url" => getBaseUrl(),
|
||||
"potentialAction" => [
|
||||
"@type" => "DonateAction"
|
||||
]
|
||||
], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
|
||||
?>
|
||||
|
||||
<!-- Script pour éviter le flash en mode sombre -->
|
||||
<script>
|
||||
|
||||
+1
-1
@@ -94,6 +94,6 @@
|
||||
</div>
|
||||
|
||||
<div class="footer-copyright">
|
||||
<?php echo LEGAL_COPYRIGHT; ?> <?php echo date('Y'); ?> - Licence libre <a href="<?php echo LEGAL_LICENSE_URL; ?>" target="_blank" rel="noopener noreferrer">GNU AGPL-V3</a>
|
||||
<?php echo LEGAL_COPYRIGHT; ?> <?php echo date('Y'); ?> - Licence libre <a href="<?php echo LEGAL_LICENSE_URL; ?>" target="_blank" rel="noopener noreferrer"><?php echo LEGAL_LICENSE; ?></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -29,7 +29,7 @@ function generateWebSiteJsonLd() {
|
||||
],
|
||||
"publisher" => [
|
||||
"@type" => "Organization",
|
||||
"name" => "OKI",
|
||||
"name" => ORGANIZATION_NAME,
|
||||
"url" => $baseUrl,
|
||||
"logo" => [
|
||||
"@type" => "ImageObject",
|
||||
@@ -69,6 +69,8 @@ function generateVideoObjectJsonLd($videoData, $video) {
|
||||
? truncateText(strip_tags($video['description']), 300)
|
||||
: "Regardez cette vidéo sur " . SITE_NAME,
|
||||
"url" => $videoUrl,
|
||||
"embedUrl" => PEERTUBE_URL . "/videos/embed/" . $video['id'],
|
||||
"inLanguage" => "fr-FR",
|
||||
"thumbnailUrl" => $thumbnailUrl,
|
||||
"uploadDate" => formatDateISO8601($video['date']),
|
||||
"duration" => $duration,
|
||||
@@ -159,6 +161,147 @@ function generateVideoObjectJsonLd($videoData, $video) {
|
||||
return json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Génère le JSON-LD pour un podcast (PodcastSeries + PodcastEpisode + AudioObject)
|
||||
*
|
||||
* @param array $episodes Épisodes formatés par getCastopodEpisodes()
|
||||
* @return string JSON-LD pour le podcast, chaîne vide si aucun épisode
|
||||
*/
|
||||
function generatePodcastJsonLd($episodes) {
|
||||
if (empty($episodes)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$baseUrl = getBaseUrl();
|
||||
$first = $episodes[0];
|
||||
|
||||
// Informations de la série, déduites du flux RSS
|
||||
$seriesName = !empty($first['podcastTitle']) ? $first['podcastTitle'] : SITE_NAME;
|
||||
$seriesUrl = !empty($first['podcastLink']) ? $first['podcastLink'] : $baseUrl;
|
||||
$seriesImage = !empty($first['image']) ? $first['image'] : $baseUrl . '/img/logo.png';
|
||||
$webFeed = !empty($first['podcastSlug'])
|
||||
? rtrim(CASTOPOD_URL, '/') . '/@' . $first['podcastSlug'] . '/feed'
|
||||
: null;
|
||||
|
||||
$series = [
|
||||
"@type" => "PodcastSeries",
|
||||
"@id" => $seriesUrl . '#podcast',
|
||||
"name" => $seriesName,
|
||||
"url" => $seriesUrl,
|
||||
"image" => $seriesImage,
|
||||
"inLanguage" => "fr-FR",
|
||||
"author" => [
|
||||
"@type" => "Organization",
|
||||
"name" => ORGANIZATION_NAME,
|
||||
"url" => $baseUrl
|
||||
],
|
||||
"publisher" => [
|
||||
"@type" => "Organization",
|
||||
"name" => SITE_NAME,
|
||||
"url" => $baseUrl,
|
||||
"logo" => [
|
||||
"@type" => "ImageObject",
|
||||
"url" => $baseUrl . "/img/logo.png"
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
if ($webFeed) {
|
||||
$series["webFeed"] = $webFeed;
|
||||
}
|
||||
|
||||
$episodeItems = [];
|
||||
foreach ($episodes as $episode) {
|
||||
$item = [
|
||||
"@type" => "PodcastEpisode",
|
||||
"name" => $episode['title'],
|
||||
"url" => $episode['link'],
|
||||
"partOfSeries" => ["@id" => $seriesUrl . '#podcast']
|
||||
];
|
||||
|
||||
if (!empty($episode['pubDate'])) {
|
||||
$item["datePublished"] = formatDateISO8601($episode['pubDate']);
|
||||
}
|
||||
if (!empty($episode['image'])) {
|
||||
$item["image"] = $episode['image'];
|
||||
}
|
||||
if (!empty($episode['description'])) {
|
||||
$item["description"] = truncateText($episode['description'], 300);
|
||||
}
|
||||
|
||||
$seconds = parseDurationToSeconds($episode['duration'] ?? '');
|
||||
if ($seconds > 0) {
|
||||
$item["timeRequired"] = formatDurationISO8601($seconds);
|
||||
}
|
||||
|
||||
if (!empty($episode['audioUrl'])) {
|
||||
$audio = [
|
||||
"@type" => "AudioObject",
|
||||
"contentUrl" => $episode['audioUrl']
|
||||
];
|
||||
$format = guessAudioEncodingFormat($episode['audioUrl']);
|
||||
if ($format !== null) {
|
||||
$audio["encodingFormat"] = $format;
|
||||
}
|
||||
$item["associatedMedia"] = $audio;
|
||||
}
|
||||
|
||||
$episodeItems[] = $item;
|
||||
}
|
||||
|
||||
$data = [
|
||||
"@context" => "https://schema.org",
|
||||
"@graph" => array_merge([$series], $episodeItems)
|
||||
];
|
||||
|
||||
return json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convertit une durée iTunes en secondes
|
||||
* Formats acceptés : "3600", "90", "MM:SS", "HH:MM:SS"
|
||||
*
|
||||
* @param string $duration Durée brute issue du flux RSS
|
||||
* @return int Durée en secondes (0 si non parsable)
|
||||
*/
|
||||
function parseDurationToSeconds($duration) {
|
||||
$duration = trim((string) $duration);
|
||||
if ($duration === '') {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strpos($duration, ':') !== false) {
|
||||
$parts = array_map('intval', explode(':', $duration));
|
||||
$seconds = 0;
|
||||
foreach ($parts as $part) {
|
||||
$seconds = $seconds * 60 + $part;
|
||||
}
|
||||
return $seconds;
|
||||
}
|
||||
|
||||
return max(0, (int) $duration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Déduit le type MIME d'un fichier audio depuis son extension
|
||||
*
|
||||
* @param string $url URL du fichier audio
|
||||
* @return string|null Type MIME (audio/mpeg, audio/mp4, audio/ogg) ou null
|
||||
*/
|
||||
function guessAudioEncodingFormat($url) {
|
||||
$extension = strtolower(pathinfo(parse_url($url, PHP_URL_PATH) ?? '', PATHINFO_EXTENSION));
|
||||
$map = [
|
||||
'mp3' => 'audio/mpeg',
|
||||
'm4a' => 'audio/mp4',
|
||||
'mp4' => 'audio/mp4',
|
||||
'ogg' => 'audio/ogg',
|
||||
'opus' => 'audio/ogg',
|
||||
'wav' => 'audio/wav'
|
||||
];
|
||||
|
||||
return $map[$extension] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Génère le JSON-LD pour les fils d'Ariane (BreadcrumbList)
|
||||
*
|
||||
|
||||
@@ -13,6 +13,12 @@ if (defined('COUNTDOWN_ENABLED') && COUNTDOWN_ENABLED === true) {
|
||||
require_once 'includes/structured-data.php';
|
||||
// Appliquer les en-têtes de sécurité
|
||||
setSecurityHeaders();
|
||||
|
||||
// Récupérer les épisodes Castopod (réutilisés pour le JSON-LD et l'affichage)
|
||||
$castopodEpisodes = [];
|
||||
if (defined('CASTOPOD_ENABLED') && CASTOPOD_ENABLED && defined('CASTOPOD_URL') && !empty(CASTOPOD_URL)) {
|
||||
$castopodEpisodes = getCastopodEpisodes();
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
@@ -21,6 +27,8 @@ setSecurityHeaders();
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="csrf-token" content="<?php echo generateCSRFToken(); ?>">
|
||||
<title><?php echo SITE_NAME; ?></title>
|
||||
<meta name="description" content="<?php echo htmlspecialchars(SITE_DESCRIPTION); ?>">
|
||||
<link rel="canonical" href="<?php echo getBaseUrl() . '/'; ?>">
|
||||
<link rel="stylesheet" href="css/styles.css?v=<?php echo filemtime('css/styles.css'); ?>">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.0.1/css/all.min.css">
|
||||
<link rel="stylesheet" href="css/mastodon-timeline.min.css?v=<?php echo filemtime('css/mastodon-timeline.min.css'); ?>">
|
||||
@@ -54,9 +62,9 @@ setSecurityHeaders();
|
||||
|
||||
<!-- Open Graph Meta Tags -->
|
||||
<meta property="og:title" content="<?php echo SITE_NAME; ?>">
|
||||
<meta property="og:description" content="Découvrez notre plateforme multimédia avec des vidéos, des shorts et des directs. Tendances, catégories et contenus exclusifs vous attendent.">
|
||||
<meta property="og:image" content="<?php echo 'https://' . $_SERVER['HTTP_HOST'] . '/img/logo.png'; ?>">
|
||||
<meta property="og:url" content="<?php echo 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; ?>">
|
||||
<meta property="og:description" content="<?php echo htmlspecialchars(SITE_DESCRIPTION); ?>">
|
||||
<meta property="og:image" content="<?php echo getBaseUrl() . '/img/logo.png'; ?>">
|
||||
<meta property="og:url" content="<?php echo getBaseUrl() . '/'; ?>">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="<?php echo SITE_NAME; ?>">
|
||||
<meta property="og:locale" content="fr_FR">
|
||||
@@ -64,8 +72,8 @@ setSecurityHeaders();
|
||||
<!-- Twitter Card Meta Tags -->
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="<?php echo SITE_NAME; ?>">
|
||||
<meta name="twitter:description" content="Découvrez notre plateforme multimédia avec des vidéos, des shorts et des directs. Tendances, catégories et contenus exclusifs vous attendent.">
|
||||
<meta name="twitter:image" content="<?php echo 'https://' . $_SERVER['HTTP_HOST'] . '/img/logo.png'; ?>">
|
||||
<meta name="twitter:description" content="<?php echo htmlspecialchars(SITE_DESCRIPTION); ?>">
|
||||
<meta name="twitter:image" content="<?php echo getBaseUrl() . '/img/logo.png'; ?>">
|
||||
|
||||
<!-- Données structurées JSON-LD pour le site web -->
|
||||
<?php
|
||||
@@ -78,6 +86,11 @@ setSecurityHeaders();
|
||||
];
|
||||
$breadcrumbJsonLd = generateBreadcrumbJsonLd($breadcrumbs);
|
||||
outputJsonLd($breadcrumbJsonLd);
|
||||
|
||||
// Données structurées du podcast (PodcastSeries + PodcastEpisode)
|
||||
if (!empty($castopodEpisodes)) {
|
||||
outputJsonLd(generatePodcastJsonLd($castopodEpisodes));
|
||||
}
|
||||
?>
|
||||
|
||||
<!-- Script pour éviter le flash en mode sombre -->
|
||||
@@ -105,6 +118,7 @@ setSecurityHeaders();
|
||||
<?php include 'includes/sidebar.php'; ?>
|
||||
<!-- Contenu principal -->
|
||||
<main class="main-content" id="main-content" role="main">
|
||||
<h1 class="sr-only"><?php echo SITE_NAME . ' — ' . SITE_DESCRIPTION; ?></h1>
|
||||
<?php include 'includes/header.php'; ?>
|
||||
<!-- Hero and Mastodon container -->
|
||||
<div class="hero-mastodon-wrapper">
|
||||
@@ -130,8 +144,7 @@ setSecurityHeaders();
|
||||
</div>
|
||||
<div class="castopod-episodes-list">
|
||||
<?php
|
||||
$castopodEpisodes = getCastopodEpisodes();
|
||||
|
||||
// $castopodEpisodes a été récupéré en début de page (JSON-LD + affichage)
|
||||
if (empty($castopodEpisodes)) {
|
||||
echo '<div class="castopod-no-episodes">Aucun épisode disponible</div>';
|
||||
} else {
|
||||
@@ -390,7 +403,7 @@ setSecurityHeaders();
|
||||
<section class="video-section" aria-labelledby="shorts-heading">
|
||||
<div class="section-header">
|
||||
<div class="section-logo">
|
||||
<img src="img/logo.png" alt="Logo <?php echo SITE_NAME; ?>" aria-hidden="true">
|
||||
<img src="img/logo.png" alt="" aria-hidden="true">
|
||||
</div>
|
||||
<h2 id="shorts-heading" class="section-title">Shorts</h2>
|
||||
</div>
|
||||
@@ -446,7 +459,7 @@ setSecurityHeaders();
|
||||
<section class="video-section" aria-labelledby="recent-videos-heading">
|
||||
<header class="section-header">
|
||||
<div class="section-logo">
|
||||
<img src="img/logo.png" alt="Logo <?php echo SITE_NAME; ?>" aria-hidden="true">
|
||||
<img src="img/logo.png" alt="" aria-hidden="true">
|
||||
</div>
|
||||
<h2 id="recent-videos-heading" class="section-title">Dernières vidéos</h2>
|
||||
</header>
|
||||
@@ -508,7 +521,7 @@ setSecurityHeaders();
|
||||
<section class="video-section" aria-labelledby="trending-videos-heading">
|
||||
<header class="section-header">
|
||||
<div class="section-logo">
|
||||
<img src="img/logo.png" alt="Logo <?php echo SITE_NAME; ?>" aria-hidden="true">
|
||||
<img src="img/logo.png" alt="" aria-hidden="true">
|
||||
</div>
|
||||
<h2 id="trending-videos-heading" class="section-title">Tendances</h2>
|
||||
</header>
|
||||
@@ -526,7 +539,7 @@ setSecurityHeaders();
|
||||
?>
|
||||
<article class="video-card" data-video-id="<?php echo $video['id']; ?>">
|
||||
<div class="video-thumbnail">
|
||||
<img src="<?php echo $video['thumbnail']; ?>" alt="<?php echo $video['title']; ?>">
|
||||
<img src="<?php echo htmlspecialchars($video['thumbnail']); ?>" alt="<?php echo htmlspecialchars($video['title']); ?>">
|
||||
<div class="video-play-icon">
|
||||
<i class="fas fa-play-circle"></i>
|
||||
</div>
|
||||
@@ -577,7 +590,7 @@ setSecurityHeaders();
|
||||
<section class="video-section" data-category-id="<?php echo $category['id']; ?>" aria-labelledby="category-heading-<?php echo $category['id']; ?>">
|
||||
<header class="section-header">
|
||||
<div class="section-logo">
|
||||
<img src="img/logo.png" alt="Logo <?php echo SITE_NAME; ?>" aria-hidden="true">
|
||||
<img src="img/logo.png" alt="" aria-hidden="true">
|
||||
</div>
|
||||
<h2 id="category-heading-<?php echo $category['id']; ?>" class="section-title"><?php echo htmlspecialchars($category['name']); ?></h2>
|
||||
</header>
|
||||
@@ -586,7 +599,7 @@ setSecurityHeaders();
|
||||
<?php foreach ($category['videos'] as $video): ?>
|
||||
<article class="video-card" data-video-id="<?php echo $video['id']; ?>">
|
||||
<div class="video-thumbnail">
|
||||
<img src="<?php echo $video['thumbnail']; ?>" alt="<?php echo $video['title']; ?>">
|
||||
<img src="<?php echo htmlspecialchars($video['thumbnail']); ?>" alt="<?php echo htmlspecialchars($video['title']); ?>">
|
||||
<div class="video-play-icon">
|
||||
<i class="fas fa-play-circle"></i>
|
||||
</div>
|
||||
|
||||
+18
-16
@@ -1,9 +1,17 @@
|
||||
<?php
|
||||
// Inclure la configuration
|
||||
require_once 'includes/config.php';
|
||||
// Appliquer les en-têtes de sécurité
|
||||
setSecurityHeaders();
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Mentions Légales - ANNU KUTE CED</title>
|
||||
<title>Mentions Légales - <?php echo SITE_NAME; ?></title>
|
||||
<meta name="description" content="Consultez les mentions légales de <?php echo SITE_NAME; ?>. Informations légales, conditions d'utilisation et politique de confidentialité.">
|
||||
<link rel="canonical" href="<?php echo 'https://' . $_SERVER['HTTP_HOST'] . '/mentions-legales.php'; ?>">
|
||||
<link rel="stylesheet" href="css/styles.css?v=<?php echo filemtime('css/styles.css'); ?>">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.0.1/css/all.min.css">
|
||||
|
||||
@@ -13,25 +21,25 @@
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="img/favicon-16x16.png">
|
||||
<link rel="manifest" href="site.webmanifest">
|
||||
<link rel="icon" type="image/x-icon" href="img/favicon.ico">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
<meta name="theme-color" content="#FF0000">
|
||||
|
||||
<!-- Open Graph Meta Tags -->
|
||||
<meta property="og:title" content="Mentions Légales - ANNU KUTE CED">
|
||||
<meta property="og:description" content="Consultez les mentions légales d'ANNU KUTE CED. Informations légales, conditions d'utilisation et politique de confidentialité du hub multimédia du podcast.">
|
||||
<meta property="og:title" content="Mentions Légales - <?php echo SITE_NAME; ?>">
|
||||
<meta property="og:description" content="Consultez les mentions légales de <?php echo SITE_NAME; ?>. Informations légales, conditions d'utilisation et politique de confidentialité.">
|
||||
<meta property="og:image" content="<?php echo 'https://' . $_SERVER['HTTP_HOST'] . '/img/logo.png'; ?>">
|
||||
<meta property="og:url" content="<?php echo 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; ?>">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="ANNU KUTE CED">
|
||||
<meta property="og:site_name" content="<?php echo SITE_NAME; ?>">
|
||||
<meta property="og:locale" content="fr_FR">
|
||||
|
||||
<!-- Twitter Card Meta Tags -->
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="Mentions Légales - ANNU KUTE CED">
|
||||
<meta name="twitter:description" content="Consultez les mentions légales d'ANNU KUTE CED. Informations légales, conditions d'utilisation et politique de confidentialité du hub multimédia du podcast.">
|
||||
<meta name="twitter:title" content="Mentions Légales - <?php echo SITE_NAME; ?>">
|
||||
<meta name="twitter:description" content="Consultez les mentions légales de <?php echo SITE_NAME; ?>. Informations légales, conditions d'utilisation et politique de confidentialité.">
|
||||
<meta name="twitter:image" content="<?php echo 'https://' . $_SERVER['HTTP_HOST'] . '/img/logo.png'; ?>">
|
||||
|
||||
<!-- Script pour éviter le flash en mode sombre -->
|
||||
<script>
|
||||
<script nonce="<?php echo getCspNonce(); ?>">
|
||||
(function() {
|
||||
const savedTheme = localStorage.getItem('theme');
|
||||
const systemPrefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||
@@ -44,12 +52,6 @@
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<?php
|
||||
// Inclure la configuration
|
||||
require_once 'includes/config.php';
|
||||
// Appliquer les en-têtes de sécurité
|
||||
setSecurityHeaders();
|
||||
?>
|
||||
<?php include 'includes/sidebar.php'; ?>
|
||||
<!-- Contenu principal -->
|
||||
<div class="main-content">
|
||||
@@ -58,9 +60,9 @@
|
||||
<!-- Section Mentions Légales -->
|
||||
<div class="section-header">
|
||||
<div class="section-logo">
|
||||
<img src="img/logo.png" alt="ANNU KUTE CED">
|
||||
<img src="img/logo.png" alt="<?php echo SITE_NAME; ?>">
|
||||
</div>
|
||||
<h2 class="section-title">Mentions Légales</h2>
|
||||
<h1 class="section-title">Mentions Légales</h1>
|
||||
</div>
|
||||
|
||||
<div class="info-section">
|
||||
|
||||
+13
-6
@@ -53,6 +53,13 @@ if ($resultsCount > 0) {
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title><?php echo !empty($query) ? 'Recherche: ' . htmlspecialchars($query) . ' - ' : 'Recherche - '; ?><?php echo SITE_NAME; ?></title>
|
||||
<meta name="description" content="<?php echo !empty($query) ? 'Résultats de recherche pour « ' . htmlspecialchars($query) . ' » sur ' . SITE_NAME . '. Découvrez des vidéos correspondantes à votre recherche.' : 'Recherchez des vidéos sur ' . SITE_NAME . '. ' . SITE_DESCRIPTION; ?>">
|
||||
<?php if (!empty($query)): ?>
|
||||
<meta name="robots" content="noindex, follow">
|
||||
<link rel="canonical" href="<?php echo getBaseUrl() . '/recherche.php?q=' . urlencode($query); ?>">
|
||||
<?php else: ?>
|
||||
<link rel="canonical" href="<?php echo getBaseUrl() . '/recherche.php'; ?>">
|
||||
<?php endif; ?>
|
||||
<link rel="stylesheet" href="css/styles.css?v=<?php echo filemtime('css/styles.css'); ?>">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.0.1/css/all.min.css">
|
||||
|
||||
@@ -62,11 +69,11 @@ if ($resultsCount > 0) {
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="img/favicon-16x16.png">
|
||||
<link rel="manifest" href="site.webmanifest">
|
||||
<link rel="icon" type="image/x-icon" href="img/favicon.ico">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
<meta name="theme-color" content="#FF0000">
|
||||
|
||||
<!-- Open Graph Meta Tags -->
|
||||
<meta property="og:title" content="<?php echo !empty($query) ? 'Recherche: ' . htmlspecialchars($query) . ' - ' : 'Recherche - '; ?><?php echo SITE_NAME; ?>">
|
||||
<meta property="og:description" content="<?php echo !empty($query) ? 'Résultats de recherche pour \"' . htmlspecialchars($query) . '\" sur ' . SITE_NAME . '. Découvrez des vidéos correspondantes à votre recherche.' : 'Recherchez des vidéos sur ' . SITE_NAME . '. Plateforme multimédia avec un contenu de qualité et exclusif.'; ?>">
|
||||
<meta property="og:description" content="<?php echo !empty($query) ? 'Résultats de recherche pour « ' . htmlspecialchars($query) . ' » sur ' . SITE_NAME . '. Découvrez des vidéos correspondantes à votre recherche.' : 'Recherchez des vidéos sur ' . SITE_NAME . '. ' . SITE_DESCRIPTION; ?>">
|
||||
<meta property="og:image" content="<?php echo 'https://' . $_SERVER['HTTP_HOST'] . '/img/logo.png'; ?>">
|
||||
<meta property="og:url" content="<?php echo 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; ?>">
|
||||
<meta property="og:type" content="website">
|
||||
@@ -76,7 +83,7 @@ if ($resultsCount > 0) {
|
||||
<!-- Twitter Card Meta Tags -->
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="<?php echo !empty($query) ? 'Recherche: ' . htmlspecialchars($query) . ' - ' : 'Recherche - '; ?><?php echo SITE_NAME; ?>">
|
||||
<meta name="twitter:description" content="<?php echo !empty($query) ? 'Résultats de recherche pour \"' . htmlspecialchars($query) . '\" sur ' . SITE_NAME . '. Découvrez des vidéos correspondantes à votre recherche.' : 'Recherchez des vidéos sur ' . SITE_NAME . '. Plateforme multimédia avec un contenu de qualité et exclusif.'; ?>">
|
||||
<meta name="twitter:description" content="<?php echo !empty($query) ? 'Résultats de recherche pour « ' . htmlspecialchars($query) . ' » sur ' . SITE_NAME . '. Découvrez des vidéos correspondantes à votre recherche.' : 'Recherchez des vidéos sur ' . SITE_NAME . '. ' . SITE_DESCRIPTION; ?>">
|
||||
<meta name="twitter:image" content="<?php echo 'https://' . $_SERVER['HTTP_HOST'] . '/img/logo.png'; ?>">
|
||||
|
||||
<?php if (!empty($query) && !empty($currentPageVideos)): ?>
|
||||
@@ -132,12 +139,12 @@ if ($resultsCount > 0) {
|
||||
</div>
|
||||
<?php if (!empty($query)): ?>
|
||||
<?php if ($isTagSearch): ?>
|
||||
<h2 class="section-title">Vidéos avec le hashtag : "<?php echo htmlspecialchars($searchTag); ?>"</h2>
|
||||
<h1 class="section-title">Vidéos avec le hashtag : "<?php echo htmlspecialchars($searchTag); ?>"</h1>
|
||||
<?php else: ?>
|
||||
<h2 class="section-title">Résultats pour : "<?php echo htmlspecialchars($query); ?>"</h2>
|
||||
<h1 class="section-title">Résultats pour : "<?php echo htmlspecialchars($query); ?>"</h1>
|
||||
<?php endif; ?>
|
||||
<?php else: ?>
|
||||
<h2 class="section-title">Rechercher des vidéos</h2>
|
||||
<h1 class="section-title">Rechercher des vidéos</h1>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -120,6 +120,10 @@ if (empty($videoData) || isset($videoData['error'])) {
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title><?php echo !empty($video['title']) ? htmlspecialchars($video['title']) . ' - ' : ''; ?><?php echo SITE_NAME; ?></title>
|
||||
<meta name="description" content="<?php echo !empty($video['description']) ? htmlspecialchars(substr(strip_tags($video['description']), 0, 200)) . '...' : 'Regardez cette vidéo sur ' . SITE_NAME; ?>">
|
||||
<?php if (!isset($videoNotFound) && !empty($video)): ?>
|
||||
<link rel="canonical" href="<?php echo getBaseUrl() . '/video.php?id=' . $video['id']; ?>">
|
||||
<?php endif; ?>
|
||||
<link rel="stylesheet" href="css/styles.css?v=<?php echo filemtime('css/styles.css'); ?>">
|
||||
<link rel="stylesheet" href="css/video-page.css?v=<?php echo filemtime('css/video-page.css'); ?>">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.0.1/css/all.min.css">
|
||||
@@ -130,7 +134,7 @@ if (empty($videoData) || isset($videoData['error'])) {
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="img/favicon-16x16.png">
|
||||
<link rel="manifest" href="site.webmanifest">
|
||||
<link rel="icon" type="image/x-icon" href="img/favicon.ico">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
<meta name="theme-color" content="#FF0000">
|
||||
|
||||
<!-- Meta tags pour le partage sur les réseaux sociaux -->
|
||||
<meta property="og:title" content="<?php echo !empty($video['title']) ? htmlspecialchars($video['title']) : 'Vidéo'; ?> - <?php echo SITE_NAME; ?>">
|
||||
@@ -141,6 +145,7 @@ if (empty($videoData) || isset($videoData['error'])) {
|
||||
<meta property="og:url" content="<?php echo (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? "https" : "http") . "://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]"; ?>">
|
||||
<meta property="og:type" content="video.other">
|
||||
<meta property="og:site_name" content="<?php echo SITE_NAME; ?>">
|
||||
<meta property="og:locale" content="fr_FR">
|
||||
|
||||
<!-- Meta tags pour Twitter -->
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
|
||||
Reference in New Issue
Block a user