NEXT_Delinew/app/utils/useWordpress.js
2026-02-09 16:37:57 +01:00

282 lines
7.8 KiB
JavaScript

/**
* Fonctions utilitaires pour récupérer des données depuis WordPress REST API
* Compatible avec Next.js (client et serveur)
*/
const WORDPRESS_API_BASE = "https://deligraph.com/wp-json/wp/v2";
const PORTFOLIO_ENDPOINT = `${WORDPRESS_API_BASE}/portfolio`;
/**
* Construit une URL avec des paramètres de requête
* @param {string} baseUrl - URL de base
* @param {Object} params - Paramètres de requête
* @returns {string} URL complète avec paramètres
*/
function buildUrl(baseUrl, params = {}) {
const url = new URL(baseUrl);
Object.keys(params).forEach((key) => {
if (params[key] !== undefined && params[key] !== null) {
url.searchParams.append(key, params[key]);
}
});
return url.toString();
}
/**
* Récupère les informations d'un média WordPress par son ID
* @param {number} mediaId - ID du média WordPress
* @param {Object} fetchOptions - Options supplémentaires pour fetch
* @returns {Promise<string|null>} URL de l'image ou null si non trouvé
*/
export async function fetchMedia(mediaId, fetchOptions = {}) {
if (!mediaId) {
return null;
}
const url = `${WORDPRESS_API_BASE}/media/${mediaId}`;
try {
const response = await fetch(url, {
...fetchOptions,
});
if (!response.ok) {
if (response.status === 404) {
return null;
}
throw new Error(`Erreur HTTP: ${response.status} - ${response.statusText}`);
}
const data = await response.json();
// Retourner l'URL source de l'image
return data.source_url || null;
} catch (error) {
console.error(`Erreur lors de la récupération du média ID "${mediaId}":`, error);
return null; // Retourner null au lieu de throw pour éviter de casser le rendu
}
}
/**
* Récupère les posts de type portfolio depuis WordPress
* @param {Object} options - Options de récupération
* @param {number} options.perPage - Nombre de posts par page (défaut: 10)
* @param {number} options.page - Numéro de page (défaut: 1)
* @param {string} options.search - Terme de recherche
* @param {number} options.categories - ID de catégorie
* @param {string} options.order - Ordre de tri (asc/desc, défaut: desc)
* @param {string} options.orderby - Champ de tri (date, title, etc., défaut: date)
* @param {Object} options.fetchOptions - Options supplémentaires pour fetch (utile pour revalidate côté serveur)
* @returns {Promise<Array>} Tableau de posts portfolio
*/
export async function fetchPortfolioPosts(options = {}) {
const {
perPage = 10,
page = 1,
search,
categories,
order = "desc",
orderby = "date",
fetchOptions = {},
} = options;
const params = {
per_page: perPage,
page: page,
order: order,
orderby: orderby,
};
if (search) {
params.search = search;
}
if (categories) {
params.categories = categories;
}
const url = buildUrl(PORTFOLIO_ENDPOINT, params);
try {
const response = await fetch(url, {
...fetchOptions,
});
if (!response.ok) {
throw new Error(`Erreur HTTP: ${response.status} - ${response.statusText}`);
}
const data = await response.json();
// Récupérer les images de couverture pour chaque post en parallèle
const postsWithImages = await Promise.all(
data.map(async (post) => {
if (post.featured_media) {
try {
const mediaUrl = await fetchMedia(post.featured_media, fetchOptions);
return { ...post, featuredImageUrl: mediaUrl };
} catch (error) {
console.error(`Erreur lors de la récupération de l'image pour le post ${post.id}:`, error);
return { ...post, featuredImageUrl: null };
}
}
return { ...post, featuredImageUrl: null };
}),
);
return {
posts: postsWithImages,
totalPages: parseInt(response.headers.get("X-WP-TotalPages") || "1", 10),
total: parseInt(response.headers.get("X-WP-Total") || "0", 10),
};
} catch (error) {
console.error("Erreur lors de la récupération des posts portfolio:", error);
throw error;
}
}
/**
* Récupère un post portfolio spécifique par son slug
* @param {string} slug - Slug du post
* @param {Object} fetchOptions - Options supplémentaires pour fetch
* @returns {Promise<Object|null>} Post portfolio ou null si non trouvé
*/
export async function fetchPortfolioPostBySlug(slug, fetchOptions = {}) {
if (!slug) {
throw new Error("Le slug est requis");
}
const url = buildUrl(PORTFOLIO_ENDPOINT, { slug });
console.log("URL de recherche:", url);
try {
const response = await fetch(url, {
...fetchOptions,
});
console.log("Statut de la réponse:", response.status, response.statusText);
if (!response.ok) {
if (response.status === 404) {
console.log("Aucun post trouvé avec le paramètre slug, tentative avec fallback...");
// Fallback: récupérer tous les posts et filtrer par slug
return await fetchPortfolioPostBySlugFallback(slug, fetchOptions);
}
throw new Error(`Erreur HTTP: ${response.status} - ${response.statusText}`);
}
const data = await response.json();
console.log(
"Données reçues:",
Array.isArray(data) ? `${data.length} résultat(s)` : "Format inattendu",
data,
);
// L'API WordPress retourne un tableau même pour un seul résultat
if (Array.isArray(data)) {
if (data.length > 0) {
return data[0];
}
// Si le tableau est vide, essayer le fallback
console.log("Tableau vide, tentative avec fallback...");
return await fetchPortfolioPostBySlugFallback(slug, fetchOptions);
}
// Si ce n'est pas un tableau, retourner directement (cas où l'API retourne un objet unique)
return data;
} catch (error) {
console.error(`Erreur lors de la récupération du post portfolio "${slug}":`, error);
// En cas d'erreur, essayer le fallback
try {
return await fetchPortfolioPostBySlugFallback(slug, fetchOptions);
} catch {
throw error; // Relancer l'erreur originale
}
}
}
/**
* Fallback: récupère tous les posts et filtre par slug
* @param {string} slug - Slug du post
* @param {Object} fetchOptions - Options supplémentaires pour fetch
* @returns {Promise<Object|null>} Post portfolio ou null si non trouvé
*/
async function fetchPortfolioPostBySlugFallback(slug, fetchOptions = {}) {
console.log("Utilisation du fallback pour le slug:", slug);
try {
const allPosts = await fetchAllPortfolioPosts({ fetchOptions });
const post = allPosts.find((p) => p.slug === slug);
if (post) {
console.log("Post trouvé via fallback");
return post;
}
console.log("Aucun post trouvé avec le slug:", slug);
return null;
} catch (error) {
console.error("Erreur dans le fallback:", error);
throw error;
}
}
/**
* Récupère un post portfolio par son ID
* @param {number} id - ID du post
* @param {Object} fetchOptions - Options supplémentaires pour fetch
* @returns {Promise<Object|null>} Post portfolio ou null si non trouvé
*/
export async function fetchPortfolioPostById(id, fetchOptions = {}) {
if (!id) {
throw new Error("L'ID est requis");
}
const url = `${PORTFOLIO_ENDPOINT}/${id}`;
try {
const response = await fetch(url, {
...fetchOptions,
});
if (!response.ok) {
if (response.status === 404) {
return null;
}
throw new Error(`Erreur HTTP: ${response.status} - ${response.statusText}`);
}
return await response.json();
} catch (error) {
console.error(`Erreur lors de la récupération du post portfolio ID "${id}":`, error);
throw error;
}
}
/**
* Récupère tous les posts portfolio (sans pagination)
* @param {Object} options - Options de récupération (mêmes que fetchPortfolioPosts)
* @returns {Promise<Array>} Tableau de tous les posts portfolio
*/
export async function fetchAllPortfolioPosts(options = {}) {
const allPosts = [];
let page = 1;
let hasMore = true;
while (hasMore) {
const result = await fetchPortfolioPosts({
...options,
page,
perPage: 100, // Maximum recommandé par WordPress REST API
});
allPosts.push(...result.posts);
if (page >= result.totalPages) {
hasMore = false;
} else {
page++;
}
}
return allPosts;
}